﻿#include "StdAfx.h"
#include "UIWebBrowser.h"
#include <atlconv.h>
#include <atlcomcli.h>
#include "../Utils/downloadmgr.h"
#include <mshtml.h>

namespace DuiLib {
	////////////////////////////////////////////////////////////////////////
	//
	IMPLEMENT_DUICONTROL (CWebBrowserUI)

	CWebBrowserUI::CWebBrowserUI () {
		m_clsid = CLSID_WebBrowser;
		m_sHomePage.clear ();
	}

	bool CWebBrowserUI::DoCreateControl () {
		if (!CActiveXUI::DoCreateControl ())
			return false;
		GetManager ()->AddTranslateAccelerator (this);
		GetControl (IID_IWebBrowser2, (LPVOID*) &m_pWebBrowser2);
		if (m_bAutoNavi && !m_sHomePage.empty ()) {
			this->Navigate2 (m_sHomePage.str_view ());
		}
		RegisterEventHandler (TRUE);
		return true;
	}

	void CWebBrowserUI::ReleaseControl () {
		m_bCreated = false;
		GetManager ()->RemoveTranslateAccelerator (this);
		RegisterEventHandler (FALSE);
	}

	CWebBrowserUI::~CWebBrowserUI () {
		ReleaseControl ();
	}

	STDMETHODIMP CWebBrowserUI::GetTypeInfoCount (UINT *iTInfo) {
		*iTInfo = 0;
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::GetTypeInfo (UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) {
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::GetIDsOfNames (REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) {
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) {
		if ((riid != IID_NULL))
			return E_INVALIDARG;

		switch (dispIdMember) {
		case DISPID_BEFORENAVIGATE2:
			BeforeNavigate2 (
				pDispParams->rgvarg[6].pdispVal,
				pDispParams->rgvarg[5].pvarVal,
				pDispParams->rgvarg[4].pvarVal,
				pDispParams->rgvarg[3].pvarVal,
				pDispParams->rgvarg[2].pvarVal,
				pDispParams->rgvarg[1].pvarVal,
				pDispParams->rgvarg[0].pboolVal);
			break;
		case DISPID_COMMANDSTATECHANGE:
			CommandStateChange (
				pDispParams->rgvarg[1].lVal,
				pDispParams->rgvarg[0].boolVal);
			break;
		case DISPID_NAVIGATECOMPLETE2:
			NavigateComplete2 (
				pDispParams->rgvarg[1].pdispVal,
				pDispParams->rgvarg[0].pvarVal);
			break;
		case DISPID_NAVIGATEERROR:
			NavigateError (
				pDispParams->rgvarg[4].pdispVal,
				pDispParams->rgvarg[3].pvarVal,
				pDispParams->rgvarg[2].pvarVal,
				pDispParams->rgvarg[1].pvarVal,
				pDispParams->rgvarg[0].pboolVal);
			break;
		case DISPID_STATUSTEXTCHANGE:
			break;
			//  	case DISPID_NEWWINDOW2:
			//  		break;
		case DISPID_NEWWINDOW3:
			NewWindow3 (
				pDispParams->rgvarg[4].ppdispVal,
				pDispParams->rgvarg[3].pboolVal,
				pDispParams->rgvarg[2].uintVal,
				pDispParams->rgvarg[1].bstrVal,
				pDispParams->rgvarg[0].bstrVal);
			break;
		case DISPID_TITLECHANGE:
		{
			TitleChange (pDispParams->rgvarg[0].bstrVal);
			break;
		}
		case DISPID_DOCUMENTCOMPLETE:
		{
			DocumentComplete (
				pDispParams->rgvarg[1].pdispVal,
				pDispParams->rgvarg[0].pvarVal);

			break;
		}
		default:
			return DISP_E_MEMBERNOTFOUND;
		}
		return S_OK;
	}

	STDMETHODIMP CWebBrowserUI::QueryInterface (REFIID riid, LPVOID *ppvObject) {
		*ppvObject = nullptr;

		if (riid == IID_IDocHostUIHandler)
			*ppvObject = static_cast<IDocHostUIHandler*>(this);
		else if (riid == IID_IDispatch)
			*ppvObject = static_cast<IDispatch*>(this);
		else if (riid == IID_IServiceProvider)
			*ppvObject = static_cast<IServiceProvider*>(this);
		else if (riid == IID_IInternetSecurityManager) {
			*ppvObject = static_cast<IInternetSecurityManager*>(this);
		} else if (riid == IID_IOleCommandTarget)
			*ppvObject = static_cast<IOleCommandTarget*>(this);

		if (*ppvObject)
			AddRef ();
		return (!*ppvObject) ? E_NOINTERFACE : S_OK;
	}

	STDMETHODIMP_ (ULONG) CWebBrowserUI::AddRef () {
		InterlockedIncrement (&m_dwRef);
		return m_dwRef;
	}

	STDMETHODIMP_ (ULONG) CWebBrowserUI::Release () {
		ULONG ulRefCount = InterlockedDecrement (&m_dwRef);
		return ulRefCount;
	}

	void CWebBrowserUI::Navigate2 (faw::string_view_t lpszUrl) {
		if (lpszUrl.empty ())
			return;

		if (m_pWebBrowser2) {
			CDuiVariant url;
			url.vt = VT_BSTR;
			url.bstrVal = _bstr_t (FawTools::T_to_utf16 (lpszUrl).c_str ());
			HRESULT hr = m_pWebBrowser2->Navigate2 (&url, nullptr, nullptr, nullptr, nullptr);
		}
	}

	void CWebBrowserUI::Refresh () {
		if (m_pWebBrowser2) {
			m_pWebBrowser2->Refresh ();
		}
	}
	void CWebBrowserUI::GoBack () {
		if (m_pWebBrowser2) {
			m_pWebBrowser2->GoBack ();
		}
	}
	void CWebBrowserUI::GoForward () {
		if (m_pWebBrowser2) {
			m_pWebBrowser2->GoForward ();
		}
	}
	/// DWebBrowserEvents2
	void CWebBrowserUI::BeforeNavigate2 (IDispatch *pDisp, VARIANT *&url, VARIANT *&Flags, VARIANT *&TargetFrameName, VARIANT *&PostData, VARIANT *&Headers, VARIANT_BOOL *&Cancel) {
		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->BeforeNavigate2 (this, pDisp, url, Flags, TargetFrameName, PostData, Headers, Cancel);
		}
	}

	void CWebBrowserUI::NavigateError (IDispatch *pDisp, VARIANT * &url, VARIANT *&TargetFrameName, VARIANT *&StatusCode, VARIANT_BOOL *&Cancel) {
		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->NavigateError (this, pDisp, url, TargetFrameName, StatusCode, Cancel);
		}
	}

	void CWebBrowserUI::NavigateComplete2 (IDispatch *pDisp, VARIANT *&url) {
		CComPtr<IDispatch> spDoc;
		m_pWebBrowser2->get_Document (&spDoc);

		if (spDoc) {
			CComQIPtr<ICustomDoc, &IID_ICustomDoc> spCustomDoc (spDoc);
			if (spCustomDoc)
				spCustomDoc->SetUIHandler (this);
		}

		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->NavigateComplete2 (this, pDisp, url);
		}
	}

	void CWebBrowserUI::ProgressChange (LONG nProgress, LONG nProgressMax) {
		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->ProgressChange (this, nProgress, nProgressMax);
		}
	}

	void CWebBrowserUI::NewWindow3 (IDispatch **pDisp, VARIANT_BOOL *&Cancel, DWORD dwFlags, BSTR bstrUrlContext, BSTR bstrUrl) {
		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->NewWindow3 (this, pDisp, Cancel, dwFlags, bstrUrlContext, bstrUrl);
		}
	}
	void CWebBrowserUI::CommandStateChange (long Command, VARIANT_BOOL Enable) {
		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->CommandStateChange (this, Command, Enable);
		}
	}

	void CWebBrowserUI::TitleChange (BSTR bstrTitle) {
		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->TitleChange (this, bstrTitle);
		}
	}

	void CWebBrowserUI::DocumentComplete (IDispatch *pDisp, VARIANT *&url) {
		if (m_pWebBrowserEventHandler) {
			m_pWebBrowserEventHandler->DocumentComplete (this, pDisp, url);
		}
	}

	// IDownloadManager
	STDMETHODIMP CWebBrowserUI::Download ( /* [in] */ IMoniker *pmk, /* [in] */ IBindCtx *pbc, /* [in] */ DWORD dwBindVerb, /* [in] */ LONG grfBINDF, /* [in] */ BINDINFO *pBindInfo, /* [in] */ LPCOLESTR pszHeaders, /* [in] */ LPCOLESTR pszRedir, /* [in] */ UINT uiCP) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->Download (this, pmk, pbc, dwBindVerb, grfBINDF, pBindInfo, pszHeaders, pszRedir, uiCP);
		}
		return S_OK;
	}

	// IDocHostUIHandler
	STDMETHODIMP CWebBrowserUI::ShowContextMenu (DWORD dwID, POINT* pptPosition, IUnknown* pCommandTarget, IDispatch* pDispatchObjectHit) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->ShowContextMenu (this, dwID, pptPosition, pCommandTarget, pDispatchObjectHit);
		}
		return S_FALSE;
	}

	STDMETHODIMP CWebBrowserUI::GetHostInfo (DOCHOSTUIINFO* pInfo) {
		if (pInfo) {
			pInfo->dwFlags |= DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_NO3DOUTERBORDER;
		}
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->GetHostInfo (this, pInfo);
		}
		return S_OK;
	}

	STDMETHODIMP CWebBrowserUI::ShowUI (DWORD dwID, IOleInPlaceActiveObject* pActiveObject, IOleCommandTarget* pCommandTarget, IOleInPlaceFrame* pFrame, IOleInPlaceUIWindow* pDoc) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->ShowUI (this, dwID, pActiveObject, pCommandTarget, pFrame, pDoc);
		}
		return S_OK;
	}

	STDMETHODIMP CWebBrowserUI::HideUI () {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->HideUI (this);
		}
		return S_OK;
	}

	STDMETHODIMP CWebBrowserUI::UpdateUI () {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->UpdateUI (this);
		}
		return S_OK;
	}

	STDMETHODIMP CWebBrowserUI::EnableModeless (BOOL fEnable) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->EnableModeless (this, fEnable);
		}
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::OnDocWindowActivate (BOOL fActivate) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->OnDocWindowActivate (this, fActivate);
		}
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::OnFrameWindowActivate (BOOL fActivate) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->OnFrameWindowActivate (this, fActivate);
		}
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::ResizeBorder (LPCRECT prcBorder, IOleInPlaceUIWindow* pUIWindow, BOOL fFrameWindow) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->ResizeBorder (this, prcBorder, pUIWindow, fFrameWindow);
		}
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::TranslateAccelerator (LPMSG lpMsg, const GUID* pguidCmdGroup, DWORD nCmdID) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->TranslateAccelerator (this, lpMsg, pguidCmdGroup, nCmdID);
		}
		return S_FALSE;
	}

	LRESULT CWebBrowserUI::TranslateAccelerator (MSG *pMsg) {
		if (pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST)
			return S_FALSE;

		if (!m_pWebBrowser2)
			return E_NOTIMPL;

		// 当前Web窗口不是焦点,不处理加速键
		BOOL bIsChild = FALSE;
		HWND hTempWnd = NULL;
		HWND hWndFocus = ::GetFocus ();

		hTempWnd = hWndFocus;
		while (hTempWnd) {
			if (hTempWnd == m_hwndHost) {
				bIsChild = TRUE;
				break;
			}
			hTempWnd = ::GetParent (hTempWnd);
		}
		if (!bIsChild)
			return S_FALSE;

		IOleInPlaceActiveObject *pObj;
		if (FAILED (m_pWebBrowser2->QueryInterface (IID_IOleInPlaceActiveObject, (LPVOID *) &pObj)))
			return S_FALSE;

		HRESULT hResult = pObj->TranslateAccelerator (pMsg);
		pObj->Release ();
		return hResult;
	}

	STDMETHODIMP CWebBrowserUI::GetOptionKeyPath (LPOLESTR* pchKey, DWORD dwReserved) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->GetOptionKeyPath (this, pchKey, dwReserved);
		}
		return E_NOTIMPL;
	}

	STDMETHODIMP CWebBrowserUI::GetDropTarget (IDropTarget* pDropTarget, IDropTarget** ppDropTarget) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->GetDropTarget (this, pDropTarget, ppDropTarget);
		}
		return S_FALSE;	// 使用系统拖拽
	}

	STDMETHODIMP CWebBrowserUI::GetExternal (IDispatch** ppDispatch) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->GetExternal (this, ppDispatch);
		}
		return S_FALSE;
	}

	STDMETHODIMP CWebBrowserUI::TranslateUrl (DWORD dwTranslate, OLECHAR* pchURLIn, OLECHAR** ppchURLOut) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->TranslateUrl (this, dwTranslate, pchURLIn, ppchURLOut);
		} else {
			*ppchURLOut = 0;
			return E_NOTIMPL;
		}
	}

	STDMETHODIMP CWebBrowserUI::FilterDataObject (IDataObject* pDO, IDataObject** ppDORet) {
		if (m_pWebBrowserEventHandler) {
			return m_pWebBrowserEventHandler->FilterDataObject (this, pDO, ppDORet);
		} else {
			*ppDORet = 0;
			return E_NOTIMPL;
		}
	}

	void CWebBrowserUI::SetWebBrowserEventHandler (CWebBrowserEventHandler* pEventHandler) {
		if (pEventHandler && m_pWebBrowserEventHandler != pEventHandler)
			m_pWebBrowserEventHandler = pEventHandler;
	}

	void CWebBrowserUI::Refresh2 (int Level) {
		CDuiVariant vLevel;
		vLevel.vt = VT_I4;
		vLevel.intVal = Level;
		m_pWebBrowser2->Refresh2 (&vLevel);
	}

	void CWebBrowserUI::SetAttribute (faw::string_view_t pstrName, faw::string_view_t pstrValue) {
		if (pstrName == _T ("homepage")) {
			m_sHomePage = pstrValue;
		} else if (pstrName == _T ("autonavi")) {
			m_bAutoNavi = (FawTools::parse_bool (pstrValue));
		} else
			CActiveXUI::SetAttribute (pstrName, pstrValue);
	}

	void CWebBrowserUI::NavigateHomePage () {
		if (!m_sHomePage.empty ())
			this->NavigateUrl (m_sHomePage.str_view ());
	}

	void CWebBrowserUI::NavigateUrl (faw::string_view_t lpszUrl) {
		if (m_pWebBrowser2 && !lpszUrl.empty ()) {
			m_pWebBrowser2->Navigate ((BSTR) SysAllocString (_bstr_t (FawTools::T_to_utf16 (lpszUrl).c_str ())), nullptr, nullptr, nullptr, nullptr);
		}
	}

	faw::string_view_t CWebBrowserUI::GetClass () const {
		return _T ("WebBrowserUI");
	}

	LPVOID CWebBrowserUI::GetInterface (faw::string_view_t pstrName) {
		if (pstrName == DUI_CTRL_WEBBROWSER) return static_cast<CWebBrowserUI*>(this);
		return CActiveXUI::GetInterface (pstrName);
	}

	void CWebBrowserUI::SetHomePage (faw::string_view_t lpszUrl) {
		m_sHomePage = faw::String::format (_T ("%s"), lpszUrl.data ());
	}

	faw::string_view_t CWebBrowserUI::GetHomePage () {
		return m_sHomePage.str_view ();
	}

	void CWebBrowserUI::SetAutoNavigation (bool bAuto /*= TRUE*/) {
		if (m_bAutoNavi == bAuto)	return;

		m_bAutoNavi = bAuto;
	}

	bool CWebBrowserUI::IsAutoNavigation () {
		return m_bAutoNavi;
	}

	STDMETHODIMP CWebBrowserUI::QueryService (REFGUID guidService, REFIID riid, void** ppvObject) {
		HRESULT hr = E_NOINTERFACE;
		*ppvObject = nullptr;

		if (guidService == SID_SDownloadManager && riid == IID_IDownloadManager) {
			*ppvObject = this;
			return S_OK;
		}
		if (guidService == SID_SInternetSecurityManager && riid == IID_IInternetSecurityManager) {
			*ppvObject = this;
			return S_OK;
		}
		return hr;
	}

	HRESULT CWebBrowserUI::RegisterEventHandler (BOOL inAdvise) {
		CComPtr<IWebBrowser2> pWebBrowser;
		CComPtr<IConnectionPointContainer>  pCPC;
		CComPtr<IConnectionPoint> pCP;
		HRESULT hr = GetControl (IID_IWebBrowser2, (void**) &pWebBrowser);
		if (FAILED (hr))
			return hr;
		hr = pWebBrowser->QueryInterface (IID_IConnectionPointContainer, (void **) &pCPC);
		if (FAILED (hr))
			return hr;
		hr = pCPC->FindConnectionPoint (DIID_DWebBrowserEvents2, &pCP);
		if (FAILED (hr))
			return hr;

		if (inAdvise) {
			hr = pCP->Advise ((IDispatch*) this, &m_dwCookie);
		} else {
			hr = pCP->Unadvise (m_dwCookie);
		}
		return hr;
	}

	DISPID CWebBrowserUI::FindId (IDispatch *pObj, LPOLESTR pName) {
		DISPID id = 0;
		if (FAILED (pObj->GetIDsOfNames (IID_NULL, &pName, 1, LOCALE_SYSTEM_DEFAULT, &id))) id = -1;
		return id;
	}

	HRESULT CWebBrowserUI::InvokeMethod (IDispatch *pObj, LPOLESTR pMehtod, VARIANT *pVarResult, VARIANT *ps, int cArgs) {
		DISPID dispid = FindId (pObj, pMehtod);
		if (dispid == -1) return E_FAIL;

		DISPPARAMS dispparams;
		dispparams.cArgs = cArgs;
		dispparams.rgvarg = ps;
		dispparams.cNamedArgs = 0;
		dispparams.rgdispidNamedArgs = nullptr;

		return pObj->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, pVarResult, nullptr, nullptr);
	}

	HRESULT CWebBrowserUI::GetProperty (IDispatch *pObj, LPOLESTR pName, VARIANT *pValue) {
		DISPID dispid = FindId (pObj, pName);
		if (dispid == -1) return E_FAIL;

		DISPPARAMS ps;
		ps.cArgs = 0;
		ps.rgvarg = nullptr;
		ps.cNamedArgs = 0;
		ps.rgdispidNamedArgs = nullptr;

		return pObj->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &ps, pValue, nullptr, nullptr);
	}

	HRESULT CWebBrowserUI::SetProperty (IDispatch *pObj, LPOLESTR pName, VARIANT *pValue) {
		DISPID dispid = FindId (pObj, pName);
		if (dispid == -1) return E_FAIL;

		DISPPARAMS ps;
		ps.cArgs = 1;
		ps.rgvarg = pValue;
		ps.cNamedArgs = 0;
		ps.rgdispidNamedArgs = nullptr;

		return pObj->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &ps, nullptr, nullptr, nullptr);
	}

	IDispatch* CWebBrowserUI::GetHtmlWindow () {
		IDispatch* pDp = nullptr;
		HRESULT hr = 0;
		if (m_pWebBrowser2)
			hr = m_pWebBrowser2->get_Document (&pDp);

		if (FAILED (hr))
			return nullptr;

		CComQIPtr<IHTMLDocument2> pHtmlDoc2 = pDp;

		if (!pHtmlDoc2)
			return nullptr;

		hr = pHtmlDoc2->get_parentWindow (&_pHtmlWnd2);

		if (FAILED (hr))
			return nullptr;

		IDispatch *pHtmlWindown = nullptr;
		hr = _pHtmlWnd2->QueryInterface (IID_IDispatch, (void**) &pHtmlWindown);
		if (FAILED (hr))
			return nullptr;

		return pHtmlWindown;
	}

	IWebBrowser2* CWebBrowserUI::GetWebBrowser2 (void) {
		return m_pWebBrowser2;
	}

	HRESULT STDMETHODCALLTYPE CWebBrowserUI::QueryStatus (__RPC__in_opt const GUID *pguidCmdGroup, ULONG cCmds, __RPC__inout_ecount_full (cCmds) OLECMD prgCmds[], __RPC__inout_opt OLECMDTEXT *pCmdText) {
		HRESULT hr = OLECMDERR_E_NOTSUPPORTED;
		return hr;
	}

	HRESULT STDMETHODCALLTYPE CWebBrowserUI::Exec (__RPC__in_opt const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, __RPC__in_opt VARIANT *pvaIn, __RPC__inout_opt VARIANT *pvaOut) {
		HRESULT hr = S_OK;

		if (pguidCmdGroup && IsEqualGUID (*pguidCmdGroup, CGID_DocHostCommandHandler)) {

			switch (nCmdID) {

			case OLECMDID_SHOWSCRIPTERROR:
			{
				IHTMLDocument2*             pDoc = nullptr;
				IHTMLWindow2*               pWindow = nullptr;
				IHTMLEventObj*              pEventObj = nullptr;
				BSTR                        rgwszNames[5] =
				{
					SysAllocString (L"errorLine"),
					SysAllocString (L"errorCharacter"),
					SysAllocString (L"errorCode"),
					SysAllocString (L"errorMessage"),
					SysAllocString (L"errorUrl")
				};
				DISPID                      rgDispIDs[5];
				VARIANT                     rgvaEventInfo[5];
				DISPPARAMS                  params;
				BOOL                        fContinueRunningScripts = true;
				int                         i;

				params.cArgs = 0;
				params.cNamedArgs = 0;

				// Get the document that is currently being viewed.
				hr = pvaIn->punkVal->QueryInterface (IID_IHTMLDocument2, (void **) &pDoc);
				// Get document.parentWindow.
				hr = pDoc->get_parentWindow (&pWindow);
				pDoc->Release ();
				// Get the window.event object.
				hr = pWindow->get_event (&pEventObj);
				// Get the error info from the window.event object.
				for (i = 0; i < 5; i++) {
					// Get the property's dispID.
					hr = pEventObj->GetIDsOfNames (IID_NULL, &rgwszNames[i], 1,
						LOCALE_SYSTEM_DEFAULT, &rgDispIDs[i]);
					// Get the value of the property.
					hr = pEventObj->Invoke (rgDispIDs[i], IID_NULL,
						LOCALE_SYSTEM_DEFAULT,
						DISPATCH_PROPERTYGET, &params, &rgvaEventInfo[i],
						nullptr, nullptr);
					SysFreeString (rgwszNames[i]);
				}

				// At this point, you would normally alert the user with 
				// the information about the error, which is now contained
				// in rgvaEventInfo[]. Or, you could just exit silently.

				(*pvaOut).vt = VT_BOOL;
				if (fContinueRunningScripts) {
					// Continue running scripts on the page.
					(*pvaOut).boolVal = VARIANT_TRUE;
				} else {
					// Stop running scripts on the page.
					(*pvaOut).boolVal = VARIANT_FALSE;
				}
				break;
			}
			default:
				hr = OLECMDERR_E_NOTSUPPORTED;
				break;
			}
		} else {
			hr = OLECMDERR_E_UNKNOWNGROUP;
		}
		return (hr);
	}
}